package TDALista;

import java.util.Iterator;


/**
 * Lista simplemente enlazada
 * @author Jordan
 *
 * @param <E>
 */
public class ListaSE<E> implements PositionList<E> {
	private NodoS<E> head, tail;
	private int size;
	
	/**
	 * constructor con atributos por defecto nulos
	 */
	public ListaSE(){
		head=null;
		tail=null;
		size=0;
	}
	public int size(){
		return size;
	}
	public boolean isEmpty(){
		return size==0;
	}
	
	public Position<E> first(){
		if(isEmpty())
			return null;
		return head;
	}
	
	public Position<E> last(){
		if(isEmpty())
			return null;
		return tail;
	}
	private NodoS<E> validate(Position<E> pos)throws InvalidPositionException{
		if(isEmpty())
			throw new InvalidPositionException("La lista esta vacia, por lo tanto no puede contener ningun nodo");
		if(pos==null)
			throw new InvalidPositionException("El nodo pasado como parametro es nulo");
		try{
			NodoS<E> nodo=(NodoS<E>)pos;
			return nodo;
		}catch (ClassCastException e){
			throw new InvalidPositionException("El nodo pasado como parametro no pertenece a la lista");
		}
	}
	
	public Position<E> next(Position<E> pos)throws InvalidPositionException, BoundaryViolationException{
		NodoS<E> nodo=validate(pos);
		if(nodo==tail)
			throw new BoundaryViolationException("");
		return nodo.getNext();
	}
	
	public Position<E> prev(Position<E> pos)throws InvalidPositionException, BoundaryViolationException{
		NodoS<E> nodo=validate(pos);
		if(nodo==head)
			throw new BoundaryViolationException("");
		NodoS<E> cursor=head;
		boolean encontrado=false;
		while(!encontrado && cursor!=null){
			if(cursor.getNext()==nodo)
				encontrado=true;
			else
				cursor=cursor.getNext();
		}
		if(cursor==null)
			throw new InvalidPositionException("");
		return cursor;
	}
	public void addFirst(E e){
		NodoS<E> nodoNuevo=new NodoS<E>(e,head);
		if(isEmpty())
			tail=nodoNuevo;
		head=nodoNuevo;
		size++;
			
	}
	public void addLast(E e){
		NodoS<E> nodoNuevo=new NodoS<E>(e);
		if(isEmpty())
			head=nodoNuevo;
		else
		tail.setNext(nodoNuevo);
		tail=nodoNuevo;
		size++;
	}
	public void addAfter(Position<E> pos, E e)throws InvalidPositionException{
		NodoS<E> nodo=validate(pos);
		if(nodo==tail)
			addLast(e);
		else{
			NodoS<E> nodoNuevo=new NodoS<E>(e,nodo.getNext());
			nodo.setNext(nodoNuevo);
			size++;
		}
	}
	public void addBefore(Position<E> pos, E e)throws InvalidPositionException{
		NodoS<E> nodo=validate(pos);
		if(nodo==head)
			addFirst(e);
		else{
			try {
				NodoS<E> nodoPrevio=validate(prev(pos));
				NodoS<E> nodoNuevo=new NodoS<E>(e,nodo);
				nodoPrevio.setNext(nodoNuevo);
				size++;
			} catch (BoundaryViolationException e1) {
				throw new InvalidPositionException("");
			}
		}
		
	}
	public E set(Position<E> pos, E e)throws InvalidPositionException{
		NodoS<E> nodo=validate(pos);
		E elemento=nodo.element();
		nodo.setElement(e);
		return elemento;
	}
	public E remove(Position<E> pos)throws InvalidPositionException{
		NodoS<E> nodo=validate(pos);
		E aux=nodo.element();
		try {
			if(size()==1){
				tail=null;
				head=null;
			}
			else{
				if(nodo==head)
					head=nodo.getNext();
				else{
					if(nodo==tail){
						tail=validate(prev(nodo));
						tail.setNext(null);
					}
					else{
						NodoS<E> nodoPrevio=validate(prev(nodo));
						nodoPrevio.setNext(nodo.getNext());
					}
				}
			}
		} catch (BoundaryViolationException e) {
			throw new InvalidPositionException("");
		}
		nodo.setNext(null);
		nodo.setElement(null);
		size--;
		return aux;
	}
	
	public Iterator<E> iterator(){
		return new IteradorListaSE<E>(this);
	}
	
	public Iterable<Position<E>> positions(){
		PositionList<Position<E>> lista=new ListaSE<Position<E>>();
		try {
			if(!isEmpty()){
				Position<E> cursor=first();
				boolean terminado=false;
				while(!terminado){
					lista.addLast(cursor);
					if(cursor==last())
						terminado=true;
					else
						cursor=next(cursor);
				}
			}
		}  catch (InvalidPositionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BoundaryViolationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return lista;
	}
	
	/**
	 * obtiene la posicion q tiene el elemento "t"
	 * @param t elemento a buscar la posicion
	 * @return
	 */
	public Position<E> getPosition(E t)
	{for (Position<E> p: positions())
		if (p.getElement().equals(t)) return p;
	return null; //no se encontro
	}
	
	//public Position<T> 
	//--------------------TESTEO Y CONSOLA----------------------------------------------//
	@Deprecated
	public String mostrar() {
	if (isEmpty()) return "No hay elementos en la lista.";
	else {String s="Elementos en la lista de la cabeza a la cola: ";
		 Iterable<Position<E>> sec=positions();
		 for(Position<E> p : sec)
			 s=s+" "+p.getElement();
		 return s;
		}
	}
	
	/**
	 * inserta al final de la lista el elemto "t" y muestra q se inserto
	 * @param t elemento a insertar
	 * @return
	 */
	@Deprecated
	protected String insertar(E t) {
		E aux=t;
		addLast(t);
		return "Se inserto al final de la lista el elemento "+aux;
	}
	
	@Deprecated
	public String remover(E t){
		if (isEmpty()) return "No hay elementos en la lista.";
		boolean encontre=false;
		Position<E> eliminar=null;
		for(Position<E> p : positions())
			if (!encontre && t.equals(p.getElement())) {
				encontre=true;
				eliminar=p;
			}
		if (encontre) {
			try {
				remove(eliminar);
			}
			catch (InvalidPositionException e) {}//No deberia saltar la excepcion, pues atajo si no esta.
			return "Se elimino el elemento "+t+" de la lista.";
		}
		else {return "El elemento "+t+" no se encuentra en la lista.";}
	}
	
	@Deprecated
	protected String buscar(E t){
		if (isEmpty()) return "No hay elementos en la lista.";
		boolean encontre=false;
		for(Position<E> p : positions())
		if (!encontre && t.equals(p.getElement())) {encontre=true;}
		if (encontre) return "El elemento "+t+" se encuentra en la lista.";
		else return "El elemento "+t+" no se encuentra en la lista.";
	}


}
